/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.entity.changeset;

import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.entity.entity.IValueObjData;

import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;
import io.iec.edp.caf.boot.context.CAFContext;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;


public final class InnerUtil
{
	public static ValueObjModifyChangeDetail buildNestedChange(Object changeValue)
	{
		DataValidator.checkForNullReference(changeValue, "changeValue");


		ValueObjModifyChangeDetail modifyChange = (ValueObjModifyChangeDetail)((changeValue instanceof ValueObjModifyChangeDetail) ? changeValue : null);
		if (modifyChange != null)
		{
			return modifyChange;
		}


		IValueObjData data = (IValueObjData)((changeValue instanceof IValueObjData) ? changeValue : null);
		if (data != null)
		{
			ValueObjModifyChangeDetail tempVar = new ValueObjModifyChangeDetail();
			tempVar.setData(data);
			ValueObjModifyChangeDetail change = tempVar;

			for (String propName : data.getPropertyNames())
			{
				change.getPropertyChanges().put(propName, data.getValue(propName));
			}
			return change;
		}

		throw new java.lang.IndexOutOfBoundsException("changeValue"+changeValue+ "Invalid changedValue");
	}


		///#region ChangeDetail Clone

	public static IChangeDetail clone(IChangeDetail change)
	{
		if (change == null)
		{
			return null;
		}

		ModifyChangeDetail modifyChange = (ModifyChangeDetail)((change instanceof ModifyChangeDetail) ? change : null);
		if (modifyChange != null)
		{
			return cloneModifyChange(modifyChange);
		}


		ValueObjModifyChangeDetail valueModifyChange = (ValueObjModifyChangeDetail)((change instanceof ValueObjModifyChangeDetail) ? change : null);
		if (valueModifyChange != null)
		{
			return cloneValueModifyChange(valueModifyChange);
		}


		AddChangeDetail addChange = (AddChangeDetail)((change instanceof AddChangeDetail) ? change : null);
		if (addChange != null)
		{
			return cloneAddChange(addChange);
		}


		DeleteChangeDetail deleteChange = (DeleteChangeDetail)((change instanceof DeleteChangeDetail) ? change : null);
		if (deleteChange != null)
		{
			return cloneDeleteChange(deleteChange);
		}

		throw new IllegalArgumentException("unkown changeDetail instance");
	}

	 static IChangeDetail cloneDeleteChange(DeleteChangeDetail deleteChange)
	{
		return new DeleteChangeDetail(deleteChange.getID());
	}

	 static IChangeDetail cloneAddChange(AddChangeDetail addChange)
	{
		IEntityData newData = (IEntityData)addChange.getEntityData().copy();
		return new AddChangeDetail(newData);
	}

	 static IChangeDetail cloneModifyChange(ModifyChangeDetail modifyChange)
	{
		ModifyChangeDetail rez = new ModifyChangeDetail(modifyChange.getID());

		Iterator iter=modifyChange.getPropertyChanges().entrySet().iterator();
		while (iter.hasNext())
		{
			Map.Entry pair=	(Map.Entry)iter.next();
			IChangeDetail changeValue = (IChangeDetail)((pair.getValue() instanceof IChangeDetail) ? pair.getValue() : null);
			rez.getPropertyChanges().put((String)pair.getKey(), changeValue != null ? changeValue.clone() : pair.getValue());

		}

		Iterator iterMultiLanguage = modifyChange.getMultiLanguageInfos().entrySet().iterator();
		while (iterMultiLanguage.hasNext()) {
			Map.Entry pair = (Map.Entry) iterMultiLanguage.next();
			MultiLanguageInfo info = pair.getValue() != null ? (MultiLanguageInfo) pair.getValue() : null;
			rez.getMultiLanguageInfos()
					.put((String) pair.getKey(), info.clone());
		}

		Iterator iter1 =modifyChange.getChildChanges().entrySet().iterator();
		while (iter1.hasNext())
		{
			Map.Entry pair=	(Map.Entry)iter1.next();
			if(pair.getValue()==null)
				continue;
			java.util.Map<String, IChangeDetail> value =(java.util.Map<String, IChangeDetail>) pair.getValue();
			if(value.entrySet().iterator().hasNext()==false)
				continue;
			java.util.Map<String, IChangeDetail> clonedValue = new LinkedHashMap(value.size());
			for (Map.Entry<String, IChangeDetail> childPair : value.entrySet()){
				clonedValue.put(childPair.getKey(), childPair.getValue().clone());
			}
			rez.getChildChanges().put((String)pair.getKey(),clonedValue);

			//rez.ChildChanges.put(allChildChanges.getKey(), allChildChanges.getValue().ToDictionary(item => item.getKey(), item => item.getValue().clone()));
		}

		return rez;
	}

	 static IChangeDetail cloneValueModifyChange(ValueObjModifyChangeDetail modifyChange)
	{
		ValueObjModifyChangeDetail tempVar = new ValueObjModifyChangeDetail();
		tempVar.setData(modifyChange.getData());
		ValueObjModifyChangeDetail rez = tempVar;
		Iterator iter=modifyChange.getPropertyChanges().entrySet().iterator();
		while (iter.hasNext())
		{
			Map.Entry pair=	(Map.Entry)iter.next();
			IChangeDetail changeValue = (IChangeDetail)((pair.getValue() instanceof IChangeDetail) ? pair.getValue() : null);
			rez.getPropertyChanges().put((String)pair.getKey(), changeValue != null ? changeValue.clone() : pair.getValue());
		}
		return rez;
	}

		///#endregion

	// region MultiLanguageInfo

	/**
	 * 将多语变更合并到普通变更中
	 * @param sourceMultiLanguageInfos
	 * @param targetMultiLanguageInfos
	 * @param targetChanges
	 */
	public static void mergeMultiLanguageInfoToChanges(
			Map<String, MultiLanguageInfo> sourceMultiLanguageInfos,
			Map<String, MultiLanguageInfo> targetMultiLanguageInfos,
			java.util.HashMap<String, Object> targetChanges) {
		String currentLanguage = CAFContext.current.getLanguage();
		if (sourceMultiLanguageInfos == null || sourceMultiLanguageInfos.isEmpty()) {
			return;
		}
		for (Entry<String, MultiLanguageInfo> entry : sourceMultiLanguageInfos.entrySet()) {
			if(entry.getValue().getPropValueMap().isEmpty())
				continue;

			String propName = entry.getKey().split(MultiLanguageInfo.MULTILANGUAGETOKEN)[0];
			// 更新变更集中该值
			if (targetChanges != null) {
				if (entry.getValue().getPropValueMap().containsKey(currentLanguage)) {
					targetChanges
							.put(propName, entry.getValue().getPropValueMap().get(currentLanguage));
				}
			}
			if (targetMultiLanguageInfos != null) {
				if (entry.getValue().getPropValueMap().values().stream().findFirst().get() instanceof ValueObjModifyChangeDetail){
					dealUdtMultiInfo(entry.getKey(), entry.getValue().clone(), targetMultiLanguageInfos);
				}else{
					if (targetMultiLanguageInfos.containsKey(entry.getKey())) {
						for (Entry<String, Object> entryValue : entry.getValue().clone().getPropValueMap()
								.entrySet()) {
							targetMultiLanguageInfos.get(entry.getKey()).getPropValueMap()
									.put(entryValue.getKey(), entryValue.getValue());
						}
					} else {
						targetMultiLanguageInfos.put(entry.getKey(), entry.getValue().clone());
					}
				}
			}
		}
	}

	private static void dealUdtMultiInfo(String key, MultiLanguageInfo multiInfo, Map<String, MultiLanguageInfo> targetMultiLanguageInfos){
			for (Entry<String, Object> entryValue : multiInfo.clone().getPropValueMap()
					.entrySet()) {
				Object value = entryValue.getValue();
				if (!(value instanceof ValueObjModifyChangeDetail))
					break;
				ValueObjModifyChangeDetail multiChange = (ValueObjModifyChangeDetail)value;
				if(!targetMultiLanguageInfos.containsKey(key)){
					targetMultiLanguageInfos.put(key, new MultiLanguageInfo());
				}
				MultiLanguageInfo currentDataMultiInfo = targetMultiLanguageInfos.get(key);
				if(!currentDataMultiInfo.getPropValueMap().containsKey(entryValue.getKey())){
					IValueObjData udtData = multiChange.getData();
					if(udtData == null)
						break;
					IValueObjData copyData = (IValueObjData)udtData.copy();
					currentDataMultiInfo.getPropValueMap().put(entryValue.getKey(), copyData);
				}

				IValueObjData valueData = (IValueObjData)currentDataMultiInfo.getPropValueMap().get(entryValue.getKey());
				for(Map.Entry<String, Object> changeItem :multiChange.getPropertyChanges().entrySet()){
					valueData.setValue(changeItem.getKey(), changeItem.getValue());
				}
			}
	}

	/**
	 * 将普通变更合并到多语变更中
	 * @param sourceChanges
	 * @param targetMultiLanguageInfos
	 * @param targetChanges
	 */
	public static void mergeChangesToMultiLanguageInfo(
			java.util.HashMap<String, Object> sourceChanges,
			Map<String, MultiLanguageInfo> targetMultiLanguageInfos,
			java.util.HashMap<String, Object> targetChanges) {
		String currentLanguage = CAFContext.current.getLanguage();
		if (sourceChanges == null || sourceChanges.isEmpty()) {
			return;
		}
		for (
				Entry<String, Object> entry : sourceChanges
				.entrySet()) {
			if (entry.getValue() instanceof ValueObjModifyChangeDetail)
				continue;
			String propName = entry.getKey();
			// 变更合并
			if (targetChanges != null) {
				targetChanges.put(propName, entry.getValue());
			}

			// 多语合并,此处考虑可能不是多语结构，所以仅在已包含的时候，合并进去
			if (targetMultiLanguageInfos != null) {
				String multiLanguagePropName = propName.concat(MultiLanguageInfo.MULTILANGUAGETOKEN);
				if (targetMultiLanguageInfos.containsKey(multiLanguagePropName)) {
					targetMultiLanguageInfos.get(multiLanguagePropName).getPropValueMap()
							.put(currentLanguage, entry.getValue());
				}
			}
		}
	}

	public static void resetMultiLangInfo(IMultiLanguageData source, IMultiLanguageData target) {
		target.getMultiLanguageInfos().clear();
		for(Map.Entry<String, MultiLanguageInfo> pair : source.getMultiLanguageInfos().entrySet()) {
			target.getMultiLanguageInfos().put(pair.getKey(), pair.getValue().clone());
		}
	}
	// endregion
}
